package com.open.center.crypto.aes;

import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Arrays;
import java.util.Base64;
import java.util.Optional;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.jce.provider.BouncyCastleProvider;


/**
 * 256位AES加解密
 *
 * @author Riche's
 * @since 2025/5/23
 */
@Slf4j
public class AESUtils {

    private static final BouncyCastleProvider PROVIDER = new BouncyCastleProvider();

    /**
     * 密钥：32byte, 256bit
     */
    private static final String KEY = "Povj5bGWtpcca2C3WOYICn+EE79SVgeIl0mMp3+VEjQ=";

    private static final String AES = "AES";

    /**
     * 加解密算法/加密模式/填充方式
     */
    private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";

    /**
     * 初始向量IV, 初始向量IV的长度规定为128位12个字节, 初始向量的来源为随机生成。
     */
    private static final GCMParameterSpec ivParameter;

    /**
     * 初始向量IV的长度 12个字节
     */
    private static final int IV_LENGTH = 12;

    static {
        SecureRandom random = new SecureRandom();
        byte[] ivBytes = new byte[IV_LENGTH];
        random.nextBytes(ivBytes);
        ivParameter = new GCMParameterSpec(128, ivBytes);
        Security.setProperty("crypto.policy", "unlimited");
    }

    /**
     * 解密
     */
    private static byte[] encrypt(byte[] data) throws NoSuchPaddingException, NoSuchAlgorithmException,
            InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        Key secretKey = new SecretKeySpec(Base64.getDecoder().decode(KEY.getBytes(StandardCharsets.UTF_8)), AES);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameter);
        return merge(ivParameter.getIV(), cipher.doFinal(data));
    }

    /**
     * 解密
     */
    public static String encrypt(String plaintext) throws NoSuchPaddingException, NoSuchAlgorithmException,
            InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        return Base64.getEncoder().encodeToString(encrypt(plaintext.getBytes(StandardCharsets.UTF_8)));
    }

    /**
     * 解密
     */
    private static byte[] decrypt(byte[] data) throws NoSuchPaddingException, NoSuchAlgorithmException,
            InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        Key secretKey = new SecretKeySpec(Base64.getDecoder().decode(KEY.getBytes(StandardCharsets.UTF_8)), AES);
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM, PROVIDER);
        // 分离IV, 密文, GCM默认IV长度[IV_LENGTH]: 12 byte
        byte[] ivBytes = Arrays.copyOfRange(data, 0, IV_LENGTH);
        byte[] cipherBytes = Arrays.copyOfRange(data, IV_LENGTH, data.length);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, new GCMParameterSpec(128, ivBytes));
        return cipher.doFinal(cipherBytes);
    }

    /**
     * 解密
     */
    public static String decrypt(String ciphertext) throws NoSuchPaddingException, NoSuchAlgorithmException,
            InvalidAlgorithmParameterException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        return new String(decrypt(Base64.getDecoder().decode(ciphertext)), StandardCharsets.UTF_8);
    }

    /**
     * 合并向量和密文
     */
    private static byte[] merge(byte[] iv, byte[] cipher) {
        byte[] array = new byte[iv.length + cipher.length];
        System.arraycopy(iv, 0, array, 0, iv.length);
        System.arraycopy(cipher, 0, array, iv.length, cipher.length);
        return array;
    }

    /**
     * 密钥生成器
     */
    private static String generateSecret() throws NoSuchAlgorithmException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);
        keyGenerator.init(256);
        SecretKey key = keyGenerator.generateKey();
        return Base64.getEncoder().encodeToString(key.getEncoded());
    }

    /**
     * 主方法
     */
    public static void main(String[] args) throws Exception {
        long beginTime = System.currentTimeMillis();
        String plaintext = "高级加密标准(AES, Advanced Encryption Standard)为最常见的对称加密算法，对称加密算法也就是加密和解密用相同的密钥。";
        log.info("----------[明文：{}]----------", plaintext);
        String ciphertext = encrypt(plaintext);
        log.info("----------[密文：{}]----------", ciphertext);
        String toPlaintext = decrypt(ciphertext);
        log.info("----------[还原明文：{}]----------", toPlaintext);
        log.info("------------------------------------------------");
        long endTime = System.currentTimeMillis();
        log.info("耗时：{} 毫秒", Optional.of((endTime - beginTime)));
        log.info("------------------------------------------------");
        String secretString = generateSecret();
        log.info("Base64密钥串：{}", secretString);
    }
}
